package hanxx.security.service.impl;

import hanxx.common.annotation.DataScope;
import hanxx.common.utils.*;
import hanxx.common.utils.ip.IpUtils;
import hanxx.menu.domain.SysMenu;
import hanxx.security.dao.SysUserDao;
import hanxx.security.domain.SysUser;
import hanxx.security.domain.SysUserLogin;
import hanxx.security.service.SysUserService;
import hanxx.system.page.PageDomain;
import hanxx.system.page.TableDataInfo;
import hanxx.system.service.impl.BaseServiceImpl;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.Timer;
import io.netty.util.TimerTask;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * edit:韩鑫鑫
 * 部门:产品研发三部
 **/
@Service
public class SysUserServiceImpl extends BaseServiceImpl<SysUser, SysUserDao> implements SysUserService {
    @Resource
    private AuthenticationManager authenticationManager;
    /** 可以用于用户注册时的密码加密使用 */
    @Resource
    private PasswordEncoder passwordEncoder;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private SysUserDao sysUserDao;

    @Override
    public AjaxResult login(SysUser user) {
        try {
            Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUserName(), user.getPassword()));
            SysUserLogin userLogin = (SysUserLogin) authenticate.getPrincipal();

            Map<String, Object> claims = new HashMap<>();
            //不要被userLogin.getToken()迷惑了，userLogin.getToken()只是一个uuid生成的随机值，发送到前端的是根据userLogin.getToken()这个随机值生成的token
            claims.put("login_user_uuid", userLogin.getToken());
            //claims.put("user",user);
            /** 生成token */
            String token1 = JwtUtils.acquireJWT(claims);
//            Claims claims1 = JwtUtils.parseJWT(token1);
//        String encode = passwordEncoder.encode(user.getPassword());
            //$2a$10$8pCd3p9HUtMI1cKanegOo.9rTKj65VLqVNiDbRIcXUxLTzWyAWfRK
            //正确的密码为333333
//        boolean matches = passwordEncoder.matches("333333", encode);


            flushUserLogin(userLogin);



            Map<String,Object> map = new HashMap<>();
            map.put("token",token1);
            return AjaxResult.success("登录成功",map);
        } catch (Exception e){
           return AjaxResult.error(500,"账号或者密码错误11");
        }
    }

    @Override
    public void flushUserLogin(SysUserLogin userLogin) {
        redisCache.setCacheObjectAndTime("login_user_uuid:"+userLogin.getToken(),userLogin,30, TimeUnit.MINUTES);
    }

    @Override
    public AjaxResult loginout() {
        try {
            SysUserLogin userLogin = (SysUserLogin) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            if (StringUtils.isNotNull(userLogin)){
                String redisKey = "login_user_uuid:" + userLogin.getToken();
                if (StringUtils.isNotNull(redisCache.getCacheObject(redisKey))){
                    redisCache.deleteObject(redisKey);
                }
            }
            return AjaxResult.success("退出成功");
        } catch (Exception e){
            return AjaxResult.error("退出失败！");
        }
    }

    @Override
    public TableDataInfo getUsers(SysUser sysUser, PageDomain pageDomain) {
        try {
            StringBuilder hql = new StringBuilder(" from SysUser where remark = :remark ");
            Map<String,Object> params = new HashMap<>();
            params.put("remark","1");
            List<SysUser> list = sysUserDao.list(hql.toString(), params, pageDomain);
            Long count = sysUserDao.count(hql.toString(), params);
            return new TableDataInfo(list,count);
        } catch (Exception e){
            return new TableDataInfo("查询失败");
        }
    }

    @Override
    public String importData(List<SysUser> sysUsers, boolean updateSupport) {
        return null;
    }

    /**
     * 根据条件分页查询已分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo selectAllocatedList(SysUser user, PageDomain pageDomain) {
        Map<String, Object> params = new HashMap<>();
        String sqlCount = "select count(*) ";
        String sqlContent = "select u.* ";
        String sql = " from sys_user u" +
                " join sys_user_role ur on u.user_id = ur.user_id" +
                " join sys_role r on r.role_id = ur.role_id" +
//                " where u.del_flag = '0' and r.role_id = :roleId and u.org_id=:orgId";
                " where u.del_flag = '0' and r.role_id = :roleId ";
        //  and r.role_id = #{roleId}

        params.put("roleId",user.getRoleIds()[0]);
//        params.put("orgId",user.getOrgId());

        if (StringUtils.isNotEmpty(user.getUserName())) {
            sql += " AND u.user_name like :uesrName";
            params.put("uesrName","%" + user.getUserName() + "%");
        }
        if (StringUtils.isNotEmpty(user.getPhonenumber())) {
            sql += " AND u.phonenumber like :phonenumber";
            params.put("phonenumber","%" +user.getPhonenumber() + "%");
        }

        List<SysUser> sysUserList = sysUserDao.listBySql(sqlContent + sql, params, pageDomain);
        Long count = sysUserDao.countBySql(sqlCount + sql, params);

        return new TableDataInfo(sysUserList, count);
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo selectUnallocatedList(SysUser user, PageDomain pageDomain) {
        Map<String, Object> params = new HashMap<>();
        String sqlCount = "select count(*) ";
        String sqlContent = "select u.* ";
        String sql = " from sys_user u" +
//                " where u.del_flag = '0' and u.org_id = :orgId" +
                " where u.del_flag = '0' " +
                " and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = :roleId)";

        params.put("roleId",user.getRoleIds()[0]);
//        params.put("orgId",user.getOrgId());

        if (StringUtils.isNotEmpty(user.getUserName())) {
            sql += " AND u.user_name like :uesrName";
            params.put("uesrName","%" + user.getUserName() + "%");
        }
        if (StringUtils.isNotEmpty(user.getPhonenumber())) {
            sql += " AND u.phonenumber like :phonenumber";
            params.put("phonenumber","%" +user.getPhonenumber() + "%");
        }

        List<SysUser> sysUserList = sysUserDao.listBySql(sqlContent + sql, params, pageDomain);
        Long count = sysUserDao.countBySql(sqlCount + sql, params);

        return new TableDataInfo(sysUserList, count);
    }

    @Override
    public void flashLastLoginTimeAndIp(SysUser sysUser) {
        SysUser sysUser1 = new SysUser();
        BeanUtils.copyBeanProp(sysUser1,sysUser);
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
//        String ip = "123.162.56.215";
//        String realAddressByIP = AddressUtils.getRealAddressByIP(ip);
        sysUser1.setLoginDate(DateUtils.getNowDate());
        sysUser1.setLoginIp(ip);
        update(sysUser1);
    }

    @Override
    public void threadLocal() {
        ThreadLocal<SysMenu> threadLocal = new ThreadLocal<>();
        SysMenu menu = new SysMenu();menu.setMenuId(555555l);menu.setCreateTime(DateUtils.getNowDate());
        System.out.println(threadLocal.get());
        threadLocal.remove();
    }

    @Resource
    private KafkaTemplate<String, String> kafkaTemplate;
    @Override
    public void kafkaMqProduct() {
        kafkaTemplate.send("heima", "1","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "2","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "3","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "4","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "5","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "6","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "7","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
        kafkaTemplate.send("heima", "8","yyyyyyyyyyyyyyyyyyyyyyyyyyyy");
    }

    @Override
    @KafkaListener(topics = {"heima", "topic_2", "topic_3"},groupId = "consumer_one")
    public void listen1(String foo){
        System.err.println(foo+"consumer_one");
    }

    @Override
    @KafkaListener(topics = {"heima", "topic_2", "topic_3"},groupId = "consumer_one")
    public void listen2(String foo) {
        System.err.println(foo+"consumer_two");
    }

    @Override
    public String pay(Long orgId) {
        return redisCache.pay(333l);
    }

    @Override
    public void testOtherPleace(){

    }

    @Override
    public void hashedWheelTimer() {
        Timer timer = new HashedWheelTimer();
        timer.newTimeout(timeout -> System.out.println("5s后执行"),5,TimeUnit.SECONDS);
        timer.newTimeout(timeout -> System.out.println("10s后执行"),10,TimeUnit.SECONDS);
        timer.newTimeout(new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                System.out.println("哈哈哈哈哈");
            }
        },13,TimeUnit.SECONDS);


        System.out.println("主线程结束");
    }

    private int aa = 22;
    @Autowired
    private RedissonClient redissonClient;
    @Override
    public String payRedisson(Long orgId) throws InterruptedException {
        RLock rLock1 = redissonClient.getLock("order_lock:"+orgId);
        /*第一个参数，最多等待10秒。
        * 例子：
        * 为3时，A在获得锁的3秒内，如果又有一个请求B来获取锁，则B等待，即A释放锁后B执行
        * 为3时，A在获得锁的3秒内，如果又有一个请求B来获取锁，则B取消，即A释放锁后B也不会执行*/
        /*第二个参数，表示过期时间，-1代表使用默认的过期时间30s*/
        if (rLock1.tryLock(10,-1,TimeUnit.SECONDS)){
            System.out.println("A获取锁成功");

//            System.out.println(fun2(orgId));
            /*if (aa == 0){
                System.out.println("A资源已经被使用完了！");
                rLock1.unlock();
                System.out.println("A"+aa);
                return "资源已经被使用完了！";
            } else {
                aa--;
            }*/
//            aa = 11;
            Thread.sleep(3000);
            if (aa==20){
                System.out.println("位于前面的请求");
            }
            if (aa==19){
                System.out.println("位于后面 的请求");
            }
            //释放锁
            rLock1.unlock();
            aa--;
            System.out.println("A"+aa);
            return "A处理完成";
        } else {
            System.out.println("A获取锁失败");
            return "A请稍等，正在支付";
        }
    }

    private String fun2(Long orgId){
        RLock rLock1 = redissonClient.getLock("order_lock:"+orgId);
        try {
            if (rLock1.tryLock(1,-1,TimeUnit.SECONDS)){
                System.out.println("B获取锁成功");
                aa = 22;
                Thread.sleep(4000);
                //释放锁
                rLock1.unlock();
                System.out.println("B"+aa);
                return "B处理完成";
            } else {
                System.out.println("B获取锁失败");
                return "B请稍等，正在支付";
            }
        } catch (InterruptedException e){
            System.out.println("B异常");
            return "B异常";
        }

    }

}